package com.ruoyi.common.serialize;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.ruoyi.common.annotation.Desensitization;
import com.ruoyi.common.enums.DesensitizationTypeEnum;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import java.io.IOException;

/**
 * @author : 张怀秋
 **/
@AllArgsConstructor
@NoArgsConstructor
public class DesensitizationSerialize extends JsonSerializer<String> implements ContextualSerializer {

    private DesensitizationTypeEnum type; //枚举
    private Integer startIndex; //开始位置
    private Integer endIndex; //结束位置


    /**
     * serialize方法是用于将Java对象转换为JSON格式的字符串的核心方法
     *
     * @param value              表示要被序列化的Java对象
     * @param jsonGenerator      生成和写入JSON数据流所需的方法
     * @param serializerProvider 能够查找或创建序列化器实例 可以提供序列化过程中的上下文信息以及错误处理机制。
     * @throws IOException 异常
     */
    @Override
    public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        switch (type) {
            //自定义类型脱敏
            case CUSTOMER:
                jsonGenerator.writeString(CharSequenceUtil.hide(value, startIndex, endIndex));
                break;
            // 中文姓名脱敏
            case CHINESE_NAME:
                jsonGenerator.writeString(DesensitizedUtil.chineseName(String.valueOf(value)));
                break;
            // 身份证脱敏
            case ID_CARD:
                jsonGenerator.writeString(DesensitizedUtil.idCardNum(String.valueOf(value), 1, 2));
                break;
            // 固定电话脱敏
            case FIXED_PHONE:
                jsonGenerator.writeString(DesensitizedUtil.fixedPhone(String.valueOf(value)));
                break;
            // 手机号脱敏
            case MOBILE_PHONE:
                jsonGenerator.writeString(DesensitizedUtil.mobilePhone(String.valueOf(value)));
                break;
            // 地址脱敏
            case ADDRESS:
                jsonGenerator.writeString(DesensitizedUtil.address(String.valueOf(value), 8));
                break;
            // 邮箱脱敏
            case EMAIL:
                jsonGenerator.writeString(DesensitizedUtil.email(String.valueOf(value)));
                break;
            // 密码脱敏
            case PASSWORD:
                jsonGenerator.writeString(DesensitizedUtil.password(String.valueOf(value)));
                break;
            // 中国车牌脱敏
            case CAR_LICENSE:
                jsonGenerator.writeString(DesensitizedUtil.carLicense(String.valueOf(value)));
                break;
            // 银行卡脱敏
            case BANK_CARD:
                jsonGenerator.writeString(DesensitizedUtil.bankCard(String.valueOf(value)));
                break;
            default:
                break;
        }
    }

    /**
     * 这个方法在序列化过程中起着提供上下文感知的自定义序列化器实例的作用。
     * 通常情况下，createContextual方法会在序列化过程开始时调用，允许开发者基于属性或整个序列化上下文定制返回的序列化器实例。
     * 在这个特定的例子中，方法简单地返回了null，这意味着不进行任何特殊处理，使用默认的序列化逻辑。
     * 在实际应用中，你可能会根据beanProperty中的信息创建并返回一个定制的JsonSerializer实例。
     *
     * @param serializerProvider 在方法内部可以通过它来根据当前的序列化环境动态地创建或调整序列化器
     * @param beanProperty       表示正在序列化的属性（成员变量）的信息，包含属性名称、类型、注解等元数据。
     *                           当序列化的是对象中的某个属性而非整个对象时，该参数就包含了关于该属性的重要上下文信息。
     * @return JsonSerializer
     * @throws JsonMappingException 异常
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        if (beanProperty != null) {
            //判断数据类型是否为String类型
            if (ObjectUtil.equal(beanProperty.getType().getRawClass(), String.class)) {
                Desensitization desensitization = beanProperty.getAnnotation(Desensitization.class);
                // 为null 去上下文找
                if (desensitization == null) {
                    desensitization = beanProperty.getContextAnnotation(Desensitization.class);
                }
                //不为null
                if (desensitization != null) {
                    // 创建定义的序列化类的实例并且返回，入参为注解定义的type,开始位置，结束位置。
                    return new DesensitizationSerialize(desensitization.type(), desensitization.startInclude(),
                            desensitization.endExclude());
                }
            }
            return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
        }
        return serializerProvider.findNullValueSerializer(null);
    }
}
